using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using TrafficWatcher.Infrastructure;
using TrafficWatcher.Models;
using TrafficWatcher.Models.DirectionsProvider;
using TrafficWatcher.ViewModels.Helpers;

namespace TrafficWatcher.ViewModels
{
    /// <summary>
    /// This class contains properties that the main View can data bind to.
    /// <para>
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// </para>
    /// <para>
    /// You can also use Blend to data bind with the tool's support.
    /// </para>
    /// <para>
    /// See http://www.galasoft.ch/mvvm
    /// </para>
    /// </summary>
    public class SettingsViewModel : ViewModelBase
    {
        private bool isDirty;

        private readonly Settings settings;
        private readonly IEnvironmentContext environmentContext;

        private IDirectionsProvider currentDirectionsProvider;
        private string start;
        private string finish;
        private bool doesTheApplicationRunAtStartup;
        
        //private ICollectionView directionsProvidersView;


        /// <summary>
        /// Initializes a new instance of the SettingsViewModel class.
        /// </summary>
        public SettingsViewModel(Settings settings, IEnvironmentContext environmentContext, DirectionsProviderRepository directionsProviderRepository)
        {
            this.settings = settings;
            this.environmentContext = environmentContext;
            
            DirectionsProviders = new ObservableCollection<IDirectionsProvider>(directionsProviderRepository.DirectionsProviders);

            SaveCommand = new RelayCommand(SaveSettings, () => isDirty);
            CancelCommand = new RelayCommand(CancelChangesIfThereAreAnyAndCloseWindow);
            OpenProgramHomepage = new RelayCommand(() => environmentContext.OpenUrl("google.com"));

            AssignProperties();

            if (IsInDesignMode)
            {
                // Code runs in Blend --> create design time data.
            }
            else
            {
                // Code runs "for real"
            }
        }

        private void AssignProperties()
        {
            currentDirectionsProvider = settings.CurrentDirectionsProvider;
            start = settings.Start;
            finish = settings.Finish;
            doesTheApplicationRunAtStartup = settings.DoesTheApplicationRunAtStartup;
        }

        private void SaveSettings()
        {
            settings.CurrentDirectionsProvider = CurrentDirectionsProvider;
            settings.Start = Start;
            settings.Finish = Finish;
            settings.DoesTheApplicationRunAtStartup = DoesTheApplicationRunAtStartup;

            settings.Save(environmentContext);
            
            WindowService.CloseWindow(typeof(Views.SettingsWindow));
        }

        private void CancelChangesIfThereAreAnyAndCloseWindow()
        {
            WindowService.CloseWindow(typeof(Views.SettingsWindow));
        }

        public ObservableCollection<IDirectionsProvider> DirectionsProviders { get; private set; }

        public string Start
        {
            get { return start; }
            set { SetProperty(ref start, value); }
        }

        public string Finish
        {
            get { return finish; }
            set { SetProperty(ref finish, value); }
        }

        public bool DoesTheApplicationRunAtStartup
        {
            get { return doesTheApplicationRunAtStartup; }
            set { SetProperty(ref doesTheApplicationRunAtStartup, value); }
        }

        public IDirectionsProvider CurrentDirectionsProvider
        {
            get { return currentDirectionsProvider; }
            set { SetProperty(ref currentDirectionsProvider, value); }
        }

        public RelayCommand SaveCommand { get; private set; }
        public RelayCommand CancelCommand { get; private set; }
        public RelayCommand OpenProgramHomepage { get; private set; }

        private void SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (!Equals(storage, value))
            {
                storage = value;
                isDirty = true;
                RaisePropertyChanged(propertyName);
            }
        }
    }
}